package com.uit.se6.customui.android.navigation.accordion;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.IInterface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.uit.se6.customui.R;
import com.uit.se6.customui.utils.FontUtils;

public class AccordionView extends LinearLayout {

	private enum Style {
		royal_white(0), flat_color(1);
		int id;

		Style(int id) {
			this.id = id;
		}

		static Style fromId(int id) {
			for (Style style : values()) {
				if (style.id == id)
					return style;
			}
			throw new IllegalArgumentException();
		}
	}

	private Style style = Style.royal_white;// default white

	private int style_color;
	private int style_color_shadow;

	private List<String> headersString;
	private int[] headersVisible = new int[0];
	private int marginLeft;
	private int marginRight;
	private int marginTopOfEachSection;
	private int paddingLeft;
	private int paddingRight;
	private int paddingTop;
	private int paddingBottom;

	private View[] children;// Views described in xml (user's)
	private View[] wrappedChildren;// Linear Layout, wrap the children
	private View[] headers;
	private View[] footers;
	private View[] sectionContainers;// = header + body + footer

	private Map<Integer, View> sectionByChildId = new HashMap<Integer, View>();

	private boolean initialized = false;

	private boolean includeFooter = true;

	public AccordionView(Context context, AttributeSet attrs) {
		super(context, attrs);
		if (attrs != null) {
			try {
				TypedArray ta = context.obtainStyledAttributes(attrs,
						R.styleable.Accordion_View);

				// headers
				int headersStringResource = ta.getResourceId(
						R.styleable.Accordion_View_section_headers, 0);
				if (headersStringResource == 0) {
					throw new IllegalArgumentException(
							"Please set section_headers as a references to strings array");
				}
				String[] _headersString = getResources().getStringArray(
						headersStringResource);

				headersString = new ArrayList<String>();
				for (String s : _headersString) {
					headersString.add(s);
				}

				// visibility
				int headersVisibilityResource = ta.getResourceId(
						R.styleable.Accordion_View_section_visibility, 0);
				if (headersVisibilityResource != 0) {
					headersVisible = getResources().getIntArray(
							headersVisibilityResource);
				}// else visibilities.length = 0

				// get style
				int style_int = ta.getInt(R.styleable.Accordion_View_style, -1);
				if (style_int != -1) {
					style = Style.fromId(style_int);
				}

				style_color = ta.getColor(
						R.styleable.Accordion_View_style_color, getResources()
								.getColor(R.color.color_blue));
				style_color_shadow = ta.getColor(
						R.styleable.Accordion_View_style_color_shadow,
						getResources().getColor(R.color.color_blue_dark));

				includeFooter = ta.getBoolean(
						R.styleable.Accordion_View_includeFooter, true);

				// other
				marginLeft = (int) ta.getDimension(
						R.styleable.Accordion_View_marginLeft, 0);
				marginRight = (int) ta.getDimension(
						R.styleable.Accordion_View_marginRight, 0);
				marginTopOfEachSection = (int) ta.getDimension(
						R.styleable.Accordion_View_marginBetweenSection, 0);
				paddingLeft = (int) ta.getDimension(
						R.styleable.Accordion_View_paddingLeft, 0);
				paddingRight = (int) ta.getDimension(
						R.styleable.Accordion_View_paddingRight, 0);
				paddingTop = (int) ta.getDimension(
						R.styleable.Accordion_View_paddingTop, 0);
				paddingBottom = (int) ta.getDimension(
						R.styleable.Accordion_View_paddingBottom, 0);
				ta.recycle();
			} catch (Exception e) {
				Log.e(this.getClass().getName(),
						"Exception when obtaining TypedArray: " + e.toString());
			}
		}

		setOrientation(VERTICAL);
	}

//	public void setHeaderString(int headersStringResource) {
//		headersString.clear();
//		String[] _headersString = getResources().getStringArray(
//				headersStringResource);
//		for (String s : _headersString) {
//			headersString.add(s);
//		}
//	}

//	public void setHeaderString(List<String> headersStringResource) {
//		headersString = headersStringResource;
//		LayoutInflater inflater = (LayoutInflater) getContext()
//				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//		for (int i = 0; i < getChildCount(); i++) {
//			final boolean hide = headersVisible.length > 0
//					&& headersVisible[i] == 0;
//			headers[i] = getViewHeader(inflater, i, hide);
//		}
//	}

	/**
	 * onFinishInflate is called after a view is inflated from XML. It is during
	 * a call to LayoutInflater.inflate(...) that onFinishInflate() will be
	 * called.
	 */
	@Override
	public void onFinishInflate() {
		if (initialized) {
			super.onFinishInflate();
			return;

		}

		final int childCount = getChildCount();
		sectionContainers = new View[childCount];

		children = new View[childCount];

		headers = new View[childCount];
		if (includeFooter)
			footers = new View[childCount];
		wrappedChildren = new View[childCount];

		LayoutInflater inflater = (LayoutInflater) getContext()
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		for (int i = 0; i < childCount; i++) {
			children[i] = getChildAt(i);
		}
		removeAllViews();

		for (int i = 0; i < childCount; i++) {
			final boolean hide = headersVisible.length > 0
					&& headersVisible[i] == 0;

			wrappedChildren[i] = getView(inflater, i, hide);
			headers[i] = getViewHeader(inflater, i, hide);
			if (includeFooter)
				footers[i] = getViewFooter(inflater);

			// combine view
			final LinearLayout section = new LinearLayout(getContext());
			sectionContainers[i] = section;
			section.setOrientation(LinearLayout.VERTICAL);
			section.addView(headers[i]);
			section.addView(wrappedChildren[i]);
			if (includeFooter)
				section.addView(footers[i]);

			// id of section is the id of user-define view
			sectionByChildId.put(children[i].getId(), section);

			addView(section);
		}

		initialized = true;
		super.onFinishInflate();
	}

	public void setTypeface(View topView, Typeface tf) {
		for (int i = 0; i < headers.length; i++) {
			TextView t = (TextView) headers[i]
					.findViewById(R.id.accordion_foldText);
			t.setTypeface(tf);
		}
	}

	/**
	 * Get view including header + body (content) + footer
	 * 
	 * @param id
	 *            = content id
	 * @return
	 */
	public View getSectionByChildId(int id) {
		return sectionByChildId.get(id);
	}

	/**
	 * get content view
	 * 
	 * @param id
	 * @return
	 */
	public View getChildById(int id) {
		for (int i = 0; i < wrappedChildren.length; i++) {
			View v = wrappedChildren[i].findViewById(id);
			if (v != null) {
				return v;
			}
		}
		return null;
	}

	/**
	 * Set WrapperLayout's visibility
	 * 
	 * @param position
	 * @param visibility
	 *            {@link View#GONE} and {@link View#VISIBLE}
	 */
	public void setSectionVisibility(int position, int visibility) {
		assertWrappedChildrenPosition(position);
		wrappedChildren[position].setVisibility(visibility);
		ToggleImageButton button = (ToggleImageButton) headers[position]
				.findViewById(R.id.accordion_foldButton);
		button.setState(wrappedChildren[position].getVisibility() == VISIBLE);
	}

	/**
	 * 
	 * @param position
	 * @return visibility {@link View#GONE} and {@link View#VISIBLE}
	 */
	public int getSectionVisibility(int position) {
		assertWrappedChildrenPosition(position);
		return wrappedChildren[position].getVisibility();
	}

	/**
	 * 
	 * @param position
	 * @param visibility
	 *            {@link View#GONE} and {@link View#VISIBLE}
	 */
	public void setChildVisibility(int position, int visibility) {
		assertWrappedChildrenPosition(position);
		sectionContainers[position].setVisibility(visibility);
	}

	public void toggleSection(int position) {
		assertWrappedChildrenPosition(position);

		if (wrappedChildren[position].getVisibility() == VISIBLE) {
			setSectionVisibility(position, GONE);
		} else {
			setSectionVisibility(position, VISIBLE);
		}
	}

	private View getViewHeader(LayoutInflater inflater, final int position,
			boolean hide) {
		if (headersString == null || headersString.size() == 0) {
			throw new IllegalArgumentException(
					"Please set section_headers as a references to strings array");
		}

		if (headersString.size() <= position) {
			for (int i = headersString.size(); i <= position; i++) {
				headersString.add("");
			}
		}

		View view = inflater.inflate(R.layout.accordion_header, null);

		RelativeLayout layout_parent = (RelativeLayout) view
				.findViewById(R.id.accordion_header_parent);

		((LayoutParams) layout_parent.getLayoutParams()).setMargins(marginLeft,
				marginTopOfEachSection, marginRight, 0);

		TextView textview = (TextView) view
				.findViewById(R.id.accordion_foldText);
		final ToggleImageButton button = (ToggleImageButton) view
				.findViewById(R.id.accordion_foldButton);

		// edit style here
		switch (style) {
		case flat_color:
			layout_parent.setBackgroundColor(style_color);
			button.setImageOnResource(R.drawable.accordion_white_down);
			button.setImageOffResource(R.drawable.accordion_white_up);
			textview.setTextColor(getResources().getColor(R.color.color_white));
			break;

		default:// royal_white
			layout_parent
					.setBackgroundResource(R.drawable.accordion_royalwhite_header_bg);
			button.setImageOnResource(R.drawable.accordion_royalwhite_down);
			button.setImageOffResource(R.drawable.accordion_royalwhite_up);
			textview.setTextColor(getResources().getColor(R.color.color_text));
			break;
		}

		textview.setText(headersString.get(position));
		button.setState(wrappedChildren[position].getVisibility() == VISIBLE);

		final OnClickListener listener = new OnClickListener() {

			@Override
			public void onClick(View v) {
				toggleSection(position);
			}
		};

		button.setOnClickListener(listener);
		view.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				listener.onClick(v);
				button.setState(wrappedChildren[position].getVisibility() == VISIBLE);
			}
		});

		return view;
	}

	private View getViewFooter(LayoutInflater inflater) {
		View view = inflater.inflate(R.layout.accordion_footer, null);

		RelativeLayout layout = (RelativeLayout) view
				.findViewById(R.id.accordion_footer);

		((LayoutParams) layout.getLayoutParams()).setMargins(marginLeft, 0,
				marginRight, 0);

		// edit style here
		switch (style) {

		case flat_color:
			layout.setBackgroundColor(style_color_shadow);
			break;

		default:// royal_white
			layout.setBackgroundResource(R.drawable.accordion_royalwhite_footer_bg);
			break;
		}

		return view;
	}

	private View getView(final LayoutInflater inflater, int i, boolean hide) {
		View container = inflater.inflate(R.layout.accordion_section, null);
		RelativeLayout parent = (RelativeLayout) container
				.findViewById(R.id.section_content);
		parent.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
		((LayoutParams) parent.getLayoutParams()).setMargins(marginLeft, 0,
				marginRight, 0);

		// edit style here
		switch (style) {
		case flat_color:
			parent.setBackgroundColor(Color.WHITE);
			break;

		default:// royal_white
			parent.setBackgroundResource(R.drawable.accordion_royalwhite_section);
			break;
		}

		// add user's views
		parent.addView(children[i]);

		// set id
		container.setId(i);

		// set visibility
		if (hide) {
			container.setVisibility(GONE);
		} // default VISIBLE

		return container;
	}

	/**
	 * check error
	 * 
	 * @param position
	 */
	private void assertWrappedChildrenPosition(int position) {
		if (wrappedChildren == null || position >= wrappedChildren.length) {
			throw new IllegalArgumentException("Cannot toggle section "
					+ position + ".");
		}
	}
}
